import BaseUtil from '@/BaseUtil';
import LightningEffects from '@/LightningEffects';
import ArrayUtil from '@/ArrayUtil';
import MathUtil from '@/MathUtil';
import SelectUtil from '@/SelectUtil';
import EffectUtil from '@/EffectUtil';
import SelectCommon from './SelectCommon';
import VestCommon from './VestCommon';

declare global {
    interface lightingParams {
        target?: unit;
        caster?: unit;
        isRepeat?: boolean;
        lighting?: LightningEffects;
        interval?: number;
        radius?: number;
        onTach?: (p: lightingParams, cur: unit) => void;
        effect?: string;
        loop?: number;
        tag?: 'enemy' | 'ally' | 'all';
    }
    interface 定点定高投射特效参数<T = any> {
        tarX: number;
        tarY: number;
        time: number;
        effectPath: string;
        caster?: unit;
        effect?: effect;
        curX?: number;
        curY?: number;
        maxHeight?: number;
        onReach?: (p: 定点定高投射特效参数<T>) => void;
        other?: T;
    }
    interface 弹射参数<T = any> {
        missile: string;
        missileUnit?: unit;
        caster: unit;
        target: unit;
        speed: number;
        radian?: number;
        onHit?: (p: 弹射参数) => void;
        tag?: 'enemy' | 'ally' | 'all';
        bounceCount?: number;
        bonceDis?: number;
        bonceRadian?: number;
        other?: T;
        repeat?: boolean;
        curX?: number;
        curY?: number;
        curLoop?: number;
        scale?: number;
    }
    interface 残影参数 {
        model: string;
        angle: number;
        scale?: number;
        duration: number;
        effect?: effect;
        x: number;
        y: number;
        alpha?: number;
    }
}

export default class EffectCommon {
    static lighting(p: lightingParams) {
        let defaPrama = {
            isRepeat: false,
            lighting: LightningEffects.CHAIN_LIGHTNING_PRIMARY,
            interval: 0.1,
            radius: 450,
            effect: 'Abilities\\Weapons\\Bolt\\BoltImpact.mdl',
            loop: 3,
            tag: 'enemy',
        };
        p = Object.assign(defaPrama, p);
        DestroyEffect(AddSpecialEffectTarget(p.effect, p.target, 'origin'));
        if (p.onTach) p.onTach(p, p.target);
        let prev: unit = p.target;
        let 伤害过: unit[] = [];
        if (!p.isRepeat) {
            伤害过.push(prev);
        }
        BaseUtil.onTimer(p.interval, (c) => {
            let es: unit[] = null; //选取.范围选取友军_排除中心单位(prev, p.radius);
            if (p.tag == 'enemy') {
                es = SelectCommon.getAllyUnitInRangeExcludeCenterUnit(prev, p.radius);
            } else if (p.tag == 'ally') {
                es = SelectCommon.getAllyUnitInRangeExcludeCenterUnit(prev, p.radius);
            } else {
                es = [].concat(SelectCommon.getAllyUnitInRangeExcludeCenterUnit(prev, p.radius), SelectUtil.getEnemyUnitsInRange(prev, p.radius));
            }
            if (!p.isRepeat) {
                es = es.filter((u) => !伤害过.includes(u));
            }
            let next = ArrayUtil.randomElement(es);
            if (next == null) return false;
            if (!p.isRepeat) {
                伤害过.push(next);
            }
            DestroyEffect(AddSpecialEffectTarget(p.effect, next, 'origin'));

            let light = AddLightningEx(p.lighting, false, GetUnitX(prev), GetUnitY(prev), Math.max(20, GetUnitFlyHeight(prev)), GetUnitX(next), GetUnitY(next), Math.max(20, GetUnitFlyHeight(next)));
            BaseUtil.runLater(0.5, () => {
                DestroyLightning(light);
            });
            if (p.onTach) p.onTach(p, next);
            prev = next;
            return c < p.loop;
        });
    }
    static addEffectAndDeleyRemove(tx: string, x: number, y: number, n: number, f: number = 0) {
        let ef = AddSpecialEffect(tx, x, y);
        EXEffectMatRotateZ(ef, f);
        BaseUtil.runLater(n, () => {
            DestroyEffect(ef);
        });
        return ef;
    }
    static delyRemove(ef: effect, n: number) {
        BaseUtil.runLater(n, () => {
            DestroyEffect(ef);
        });
    }
    static 定点定高投射(p: 定点定高投射特效参数) {
        p.curX = GetUnitX(p.caster);
        p.curY = GetUnitY(p.caster);
        let f = MathUtil.angleBetweenCoords(p.curX, p.curY, p.tarX, p.tarY);
        p.effect = AddSpecialEffect(p.effectPath, p.curX, p.curY);
        EXEffectMatRotateZ(p.effect, f);
        let dis = MathUtil.distanceBetweenPoints(p.curX, p.curY, p.tarX, p.tarY);
        let count = p.time * 25;
        let spd = dis / count;
        let learc = (p.maxHeight / dis) * 1.5;
        let fz = Math.max(-90, -90 * learc);
        // EXEffectMatRotateY(p.effect, fz);
        EXEffectMatRotateX(p.effect, fz);
        let rz = (fz * -2) / count;

        BaseUtil.onTimer(0.04, (c) => {
            p.curX += spd * CosBJ(f);
            p.curY += spd * SinBJ(f);
            EXSetEffectXY(p.effect, p.curX, p.curY);
            let fh = Sin((c / count) * Math.PI) * p.maxHeight;
            fh = Math.max(0, fh);
            EXSetEffectZ(p.effect, fh);
            // EXEffectMatRotateY(p.effect, rz);
            EXEffectMatRotateX(p.effect, rz);
            if (c >= count) {
                p.onReach && p.onReach(p);
                DestroyEffect(p.effect);
            }
            return c < count;
        });
        return p;
    }
    static 延迟删除闪电(l: lightning, s: number) {
        BaseUtil.runLater(s, () => {
            DestroyLightning(l);
        });
    }
    static 模拟弹射(p: 弹射参数) {
        let def: Partial<弹射参数> = {
            repeat: false,
            missile: 'Abilities\\Weapons\\ShadowHunterMissile\\ShadowHunterMissile.mdl',
            bonceDis: 500,
            bounceCount: 3,
            tag: 'enemy',
            bonceRadian: 0.15,
            curLoop: 0,
            scale: 1,
        };
        p = Object.assign(def, p);
        EffectCommon.bounceTarget(p);
    }
    private static bounceTarget(p: 弹射参数) {
        if (!IsUnitAliveBJ(p.target) || GetUnitState(p.target, UNIT_STATE_LIFE) < 0.4) {
            p.missileUnit && KillUnit(p.missileUnit);
            return false;
        }
        if (!p.curX && !p.curY) {
            p.curX = GetUnitX(p.caster);
            p.curY = GetUnitY(p.caster);
        }
        let x = p.curX;
        let y = p.curY;
        let tx = GetUnitX(p.target);
        let ty = GetUnitY(p.target);
        let ag = MathUtil.angleBetweenCoords(x, y, tx, ty);
        p.missileUnit = VestCommon.取马甲并设置(x, y, ag);
        DzSetUnitModel(p.missileUnit, p.missile);
        SetUnitScale(p.missileUnit, p.scale, p.scale, p.scale);
        let spd = p.speed / 25;

        let initDis = MathUtil.distanceBetweenPoints(x, y, tx, ty);
        let h = initDis * (p.radian ?? 0);
        h = Math.max(60, h);
        BaseUtil.onTimer(0.04, (c) => {
            if (!IsUnitAliveBJ(p.target) || GetUnitState(p.target, UNIT_STATE_LIFE) < 0.4) {
                VestCommon.returnVest(p.missileUnit);
                return false;
            }
            let tx = GetUnitX(p.target);
            let ty = GetUnitY(p.target);
            let dis = MathUtil.distanceBetweenPoints(p.curX, p.curY, tx, ty);
            let ag = MathUtil.angleBetweenCoords(p.curX, p.curY, tx, ty);
            p.curX = p.curX + CosBJ(ag) * spd;
            p.curY = p.curY + SinBJ(ag) * spd;
            SetUnitX(p.missileUnit, p.curX);
            SetUnitY(p.missileUnit, p.curY);
            EXSetUnitFacing(p.missileUnit, ag);

            let count = MathUtil.distanceBetweenPoints(x, y, tx, ty) / spd;
            let fh = Sin((c / count) * Math.PI) * h + 60;
            fh = Math.max(60, fh);
            SetUnitFlyHeight(p.missileUnit, fh, c * 1000);
            let isReached = dis <= spd;
            if (isReached) {
                p.curLoop++;
                p.onHit && p.onHit(p);
                VestCommon.returnVest(p.missileUnit);
                if (p.curLoop < p.bounceCount) {
                    let es: unit[] = null;
                    if (p.tag == 'enemy') {
                        es = SelectUtil.getEnemyUnitsInRange(p.caster, p.bonceDis, p.curX, p.curY);
                    } else if (p.tag == 'ally') {
                        es = SelectCommon.getAllyUnitInRange(p.caster, p.bonceDis, p.curX, p.curY);
                    } else {
                        es = [].concat(SelectUtil.getEnemyUnitsInRange(p.caster, p.bonceDis, p.curX, p.curY), SelectCommon.getAllyUnitInRange(p.caster, p.bonceDis, p.curX, p.curY));
                    }
                    ArrayUtil.removeElement(es, p.target);
                    if (es.length > 0) {
                        p.target = ArrayUtil.randomElement(es);
                        EffectCommon.bounceTarget(p);
                    }
                }
            }
            return !isReached;
        });
        return p;
    }
    static 残影特效(p: 残影参数) {
        p.effect = AddSpecialEffect(p.model, p.x, p.y);
        EXEffectMatRotateZ(p.effect, p.angle);
        let count = p.duration * 25;
        p.alpha = p.alpha || 255;
        let spd = p.alpha / count;
        BaseUtil.onTimer(0.04, (c) => {
            p.alpha = Math.max(0, p.alpha - spd);
            DzSetEffectVertexAlpha(p.effect, p.alpha);
            if (c >= count) {
                EffectUtil.destroyEffectNoDeathAnim(p.effect);
            }
            return c < count;
        });
    }
}
